package com.example.netty.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class NioServer {
    public static void main(String[] args) throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);
        serverSocketChannel.socket().bind(new InetSocketAddress(9000));

        Selector selector = Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        while (true) {
            System.out.println("等待事件发生");
            // 这里还是阻塞等待，
            int select = selector.select();
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey selectionKey = iterator.next();
                iterator.remove();
                handleChannel(selectionKey);
            }
        }
    }

    private static void handleChannel(SelectionKey selectionKey) {
        if (selectionKey.isAcceptable()) {
            System.out.println("有客户端发生了连接");
            ServerSocketChannel channel = (ServerSocketChannel) selectionKey.channel();
            try {
                SocketChannel client = channel.accept();
                client.configureBlocking(false);
                // 连接之后立即注册读操作，客户端发送数据过来才能监听到
                client.register(selectionKey.selector(), SelectionKey.OP_READ);
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else if (selectionKey.isReadable()) {

            System.out.println("收到客户端发送数据的请求");
            SocketChannel channel = (SocketChannel) selectionKey.channel();

            // 如果这里你不读取数据，读事件会一直触发，这是有NIO属于水平触发决定的，
            ByteBuffer allocate = ByteBuffer.allocate(1024);
            try {
                int read = channel.read(allocate);
                if (read != -1) {
                    System.out.println("客户端发送的数据:" + new String(allocate.array(), 0, read));
                }
                channel.write(ByteBuffer.wrap("你好，我是服务端".getBytes()));
                // 处理完读操作之后，需要重新注册下读操作，
                // 如果下面一行被放开，将会一直会有可写操作触发，因为网络中99.999%的情况下都是可写的，一般不监听
//                selectionKey.interestOps(SelectionKey.OP_WRITE | SelectionKey.OP_READ);
                selectionKey.interestOps(SelectionKey.OP_READ);
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else if (selectionKey.isWritable()) {
            System.out.println("触发写事件");
        }
    }
}
